﻿#include "backend.h"
#include "cameraservice.h"

#include <QAbstractVideoSurface>
#include <iostream>

CameraService::CameraService(Backend *backend, QObject *parent)
    : QObject(parent), m_backend(backend), m_isFormatSet(false)
{
    //来自Backend的帧，触发onVideoFrameReady
    connect(m_backend.data(), &Backend::frameReady, this, &CameraService::onVideoFrameReady);
}

//VideoOutput控件的source发生的事情顺序：1、调用CameraService类的构造函数。2、为videoSurface属性赋值。
//为属性videoSurface赋值，该属性存储了底层视频面（the underlaying video surface），这个视频面将帧渲染到VideoOutput
void CameraService::setVideoSurface(QAbstractVideoSurface *surface){
    if (m_surface == surface)
        return;
    if(m_surface && m_surface != surface && m_surface->isActive())
        m_surface->stop();

    m_surface = surface;//指针指向属性videoSurface的值
    m_backend->start(); //打开相机，每30ms发送Mat帧信号。然后转格式后被present。
}

//设置格式并开始显示。此函数被调用一次。
void CameraService::setFormat(
        int width,
        int height,
        QVideoFrame::PixelFormat frameFormat )
{
    QSize size(width, height);
    QVideoSurfaceFormat format(size, frameFormat);
    m_format = format;
    if (m_surface) {
        if (m_surface->isActive())
            m_surface->stop();
        m_format = m_surface->nearestFormat(m_format);
        m_surface->start(m_format);     //开始显示由present提交的帧
    }
}

//提交帧，Mat--QImage--QVideoFrame
//每30ms一次
void CameraService::onVideoFrameReady(cv::Mat currentFrame)
{
    if (!m_surface || currentFrame.empty())
        return;
    cv::Mat continuousFrame;
    if (!currentFrame.isContinuous()) //OpenCV是将像素数据连续地存储成一行的。
        continuousFrame = currentFrame.clone();
    else
        continuousFrame = currentFrame;
    if (!m_isFormatSet) {   //setFormat函数只执行一次
        setFormat(continuousFrame.cols,
                  continuousFrame.rows,
                  QVideoFrame::Format_RGB32);
        m_isFormatSet = true;
    }
    m_image = QImage(continuousFrame.data,
                     continuousFrame.cols,
                     continuousFrame.rows,
                     continuousFrame.step,
                     QImage::Format_RGB888).rgbSwapped();
    m_image.convertTo(QVideoFrame::imageFormatFromPixelFormat(QVideoFrame::Format_RGB32));  //QImage转QVideoFrame
    m_surface->present(QVideoFrame(m_image));   //提交QVideoFrame实例帧
}
